spb/internetpressure
Public
TypeScript 36.3%
Python 31.8%
Go 18%
JavaScript 9.8%
Shell 1.9%
SQL 1.4%
CSS 0.5%
1import type { Metadata } from 'next';2import Link from 'next/link';3import { AsnBgpChart } from '@/components/detail/AsnBgpChart';4import { ComponentGrid } from '@/components/detail/ComponentGrid';5import { ScopeHeader } from '@/components/detail/ScopeHeader';6import { ScopePressureChart } from '@/components/detail/ScopeCharts';7import { TargetsTable } from '@/components/detail/Tables';8import { IncidentsSection } from '@/components/incidents/IncidentsSection';9import { Section, Stat } from '@/components/ui/primitives';10import { apiGet, apiTry } from '@/lib/api';11import { fmt, fmtDelta, fmtInt, fmtPct, fmtRatio } from '@/lib/format';12import type { AsnDetail } from '@/lib/types';1314export const dynamic = 'force-dynamic';1516type Params = Promise<{ asn: string }>;1718export async function generateMetadata({ params }: { params: Params }): Promise<Metadata> {19 const { asn } = await params;20 const a = await apiTry<AsnDetail>(`/api/v1/pressure/asn/${encodeURIComponent(asn)}`);21 if (!a) return { title: `AS${asn}` };22 return { title: `AS${a.asn} ${a.name} — pressure ${fmt(a.pressure)} (${a.level_label})`, description: `Independent observation of AS${a.asn} (${a.name}): pressure ${fmt(a.pressure)}, BGP churn ${fmtRatio(a.bgp.churn_ratio)}, path stability ${fmtPct(a.bgp.path_stability)}.`, alternates: { canonical: `/asn/${a.asn}` } };23}2425export default async function AsnPage({ params }: { params: Params }) {26 const { asn } = await params;27 if (!/^\d+$/.test(asn)) {28 const { notFound } = await import('next/navigation');29 notFound();30 }31 const a = await apiGet<AsnDetail>(`/api/v1/pressure/asn/${encodeURIComponent(asn)}`);32 return (33 <div className="pb-8">34 <ScopeHeader35 kicker={`Autonomous system · ${a.country} · importance ${a.importance}/5`}36 title={`AS${a.asn} ${a.name}`}37 subtitle={<>Observed from {a.regions_observed.length} probe regions · {fmtInt(a.targets.length)} targets announced from this network</>}38 pressure={a.pressure}39 level={a.level}40 delta1h={a.delta_1h}41 trend={a.trend}42 confidence={a.confidence}43 ts={a.ts}44 meta={45 <>46 <span>47 regions{' '}48 {a.regions_observed.map((r) => (49 <Link key={r} href={`/internet/${r}`} className="mr-1 text-ink hover:text-accent">50 {r}51 </Link>52 ))}53 </span>54 </>55 }56 />5758 <Section label="Components">59 <ComponentGrid components={a.components} />60 </Section>6162 <Section label="BGP" right={<Link href="/bgp" className="hover:text-ink">global BGP dashboard →</Link>}>63 <div className="mb-4 grid grid-cols-3 gap-4 sm:grid-cols-6">64 <Stat label="prefixes 24h" value={fmtInt(a.bgp.prefixes_observed_24h)} />65 <Stat label="announcements 1h" value={fmtInt(a.bgp.announcements_1h)} />66 <Stat label="withdrawals 1h" value={fmtInt(a.bgp.withdrawals_1h)} />67 <Stat label="churn ratio" value={<span style={{ color: a.bgp.churn_ratio >= 2 ? 'var(--p-high)' : undefined }}>{fmtRatio(a.bgp.churn_ratio)}</span>} sub="vs baseline" />68 <Stat label="origin changes 1h" value={<span style={{ color: a.bgp.origin_changes_1h > 0 ? 'var(--p-elevated)' : undefined }}>{fmtInt(a.bgp.origin_changes_1h)}</span>} />69 <Stat label="path stability" value={<span style={{ color: a.bgp.path_stability < 0.9 ? 'var(--p-stressed)' : undefined }}>{fmtPct(a.bgp.path_stability)}</span>} />70 </div>71 <AsnBgpChart series={a.bgp.series_24h} />72 </Section>7374 <Section label="24 h pressure">75 <ScopePressureChart series={a.history_24h} height={220} />76 </Section>7778 <Section label="Incidents involving this ASN">79 <IncidentsSection incidents={a.incidents} />80 </Section>8182 <Section label="Targets" right={<span>{fmtInt(a.targets.length)} targets · Δ1h {fmtDelta(a.delta_1h)}</span>}>83 <TargetsTable targets={a.targets} />84 </Section>85 </div>86 );87}88